# '''
# 模拟云渲染服务器 UDP方式
# '''
import cv2, imutils, socket
import numpy as np
import time
import base64
import threading, wave,pickle,struct
import sys
from threading import Thread
import queue
import os
import ip_conf

g_test_print = 10

def init():# 初始化音频和视频的监听socket
    hostip = ip_conf.ser_ip
    lisvidport = ip_conf.ser_port
    print("Service: ", 'hostip:', hostip, 'port:', lisvidport)
    try:
        socketvid = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    except:
        print('渲染服务器创建失败')
        exit()

    socketvid.bind((hostip, lisvidport))
    # socketvid.listen(10)  # TCPsocket才能listen
    return socketvid


# 
filename =  ".//service_video//720p60fps.mp4"

vid = cv2.VideoCapture(filename) # 每个用户建一个？还有q的队列！！
FPS = vid.get(cv2.CAP_PROP_FPS)
# print(FPS, 0.5/FPS)
# # 以下五行代码的变量全局只用到一次，用于输出视频相关数据
# totalNoFrames = int(vid.get(cv2.CAP_PROP_FRAME_COUNT)) # 总帧数
# durationInSeconds = float(totalNoFrames) / float(FPS) # 传输用时
# d=vid.get(cv2.CAP_PROP_POS_MSEC)
# print(durationInSeconds, d)

def video_stream_gen(video, myq): # 生成视频流
    global g_test_print
    WIDTH = 600
    count = 0
    while(video.isOpened()):
        # try:
        _, frame = video.read()
        if frame is None:
            if count < 10:
                print('视频传输到尽头，重新传输')
                video = cv2.VideoCapture(filename)
                count += 1
                continue
            else:
                break
        frame = imutils.resize(frame, width=WIDTH) # 调整大小
        myq.put(frame)
        # if g_test_print:
        #     print(g_test_print, frame)
        #     g_test_print -= 1
        # except :
        #     print('因为这个退出？') # 真是这里
        #     os._exit(1)
    print('Player closed')
    video.release()
	

def video_stream(client_addr, qNew, video):
    global g_test_print
    clientMirror = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 跟这个客户端通信的socket
    clientMirror.setsockopt(socket.SOL_SOCKET,socket.SO_RCVBUF,65536)
    FPS = video.get(cv2.CAP_PROP_FPS)
    TS = (0.5/FPS) # 每帧花多少个0.5s？渲染采样时间 0.5/60 = 0.008  0.5/30 = 0.016
    fps, st, frames_to_count, cnt = (0, 0, 10, 0) # 这几个变量和TS都是每个用户独有的。frames_to_count应该是每多少帧检测FPS这样
    # cv2.namedWindow('TRANSMITTING VIDEO')        
    # cv2.moveWindow('TRANSMITTING VIDEO', 10, 30) 
    print('Send video to', client_addr)
    WIDTH = 600
    try:
        while(True):
            frame = qNew.get()
            encoded, buffer = cv2.imencode('.jpeg',frame,[cv2.IMWRITE_JPEG_QUALITY,80])
            message = base64.b64encode(buffer)
            clientMirror.sendto(message, client_addr)
            # print(message)
            # time.sleep(100)
            frame = cv2.putText(frame,'FPS: ' + str(round(fps,1)),(10,40),cv2.FONT_HERSHEY_SIMPLEX,0.7,(0,0,255),2)
            if cnt == frames_to_count:
                try:
                    # print("已发送一定帧率报文")
                    fps = (frames_to_count/(time.time()-st)) # 记录时间
                    st=time.time()
                    cnt = 0
                    if fps > FPS:
                        TS += 0.0001 # 粒度别太大了！
                    elif fps < FPS:
                        if TS > 0:
                            TS -= 0.0001
                    else:
                        pass
                except:
                    pass
            cnt += 1
            if TS > 1e-15:
                time.sleep(TS)
            # key = cv2.waitKey(int(1000 * TS)) & 0xFF	
            # cv2.imshow('TRANSMITTING VIDEO', frame) # 是在服务器也显示视频时才会做的检测q退出
            # if key == ord('q'):
            #     os._exit(1)
            #     TS=False
            #     break	
    except ConnectionError as ce: 
        print(f'{client_addr}断开链接')
        clientMirror.close()


vidListen = init()
while True:
    try:
        msg, addr = vidListen.recvfrom(2048)
    except:
        print('接收终端通信失败。')
        break
    print('接收', msg.decode('utf-8'), addr)
    addrSendTo = (addr[0], addr[1]+1)
    print(addrSendTo)
    videoNew = cv2.VideoCapture(filename) # 新建一个？会一个快一个慢orz咋回事
    qNew = queue.Queue(maxsize=30) # 每个用户建一个帧队列
    t1 = Thread(target=video_stream_gen, args=(videoNew, qNew, )) # 为啥它结束之后会自动服务器停掉啊？？
    t2 = Thread(target=video_stream, args=(addrSendTo, qNew, videoNew, ))
    # t1.setDaemon(True) # 能随着control-c一起退出 算了目前还是不行
    # t2.setDaemon(True)
    t1.start()
    t2.start()
vidListen.close()
